package com.zs.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 作为客户端的NIO程序
 * Created by zhangshuqing on 2017/6/1.
 */
public class TCPClientManager {

    private static TCPClientManager mInstance;
    private SocketChannel mChannel;
    private Selector mSelector;

    private ExecutorService mSendPool;
    private ReceiveThread receiveThread;

    private TCPClientManager() {
        try {
            mSendPool = Executors.newSingleThreadExecutor();
            connect();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static TCPClientManager getmInstance() {
        if (mInstance == null) {
            synchronized (TCPClientManager.class) {
                if (mInstance == null) {
                    mInstance = new TCPClientManager();
                }
            }
        }
        return mInstance;
    }


    public void connect() throws IOException {
        mChannel = SocketChannel.open();
        mSelector = Selector.open();
        mChannel.configureBlocking(false);
        mChannel.register(mSelector, SelectionKey.OP_READ);
        mChannel.connect(new InetSocketAddress("localhost", 8080));
        if (receiveThread == null) {
            receiveThread = new ReceiveThread();
        }
        receiveThread.start();

    }

    public void sendMsg(String msg) {
        mSendPool.execute(new SendWoker(msg));
    }

    /**
     * 接收数据
     */
    class ReceiveThread extends Thread {
        final ByteBuffer byteBuffer = ByteBuffer.allocate(500);

        @Override
        public void run() {
            try {
                while (true) {
                    if (mSelector.select() == 0) {
                        continue;
                    }

                    Iterator<SelectionKey> itor = mSelector.selectedKeys().iterator();
                    while (itor.hasNext()) {
                        SelectionKey key = itor.next();
                        if(key.isConnectable()){
                            mChannel.register(mSelector,SelectionKey.OP_READ);
                            mChannel.finishConnect();
                        }else if (key.isReadable()){
                            byteBuffer.clear();
                            int read=mChannel.read(byteBuffer);
                            if(read==-1){
                                key.cancel();
                                mChannel.close();

                            }
                            if(read>0){
                                byteBuffer.flip();
                                String receive= Charset.forName("utf-8").decode(byteBuffer).toString();
                                System.out.println("收到数据:"+receive);
                            }


                        }
                        itor.remove();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }


    /**
     * 发送数据
     */
    class SendWoker implements Runnable {
        private String msg;

        public SendWoker(String msg) {
            this.msg = msg;
        }

        @Override
        public void run() {
            byte[] data=msg.getBytes();
            int len=data.length+4;//body+head;
            ByteBuffer dataBuffer=ByteBuffer.allocate(len);
            dataBuffer.putInt(len);
            dataBuffer.put(dataBuffer);
            try {
                dataBuffer.flip();
                mChannel.finishConnect();
                int send_size=mChannel.write(dataBuffer);
                System.out.println("发送长度:"+send_size);
            }catch (Exception e){
                e.printStackTrace();
               if(mChannel!=null){
                   try {
                       mChannel.close();
                   } catch (IOException e1) {
                       e1.printStackTrace();
                   }
               }
            }


        }
    }


}
